#include "dxInput.h"

LPDIRECTINPUT8        g_lpDI;	// the direct input object
LPDIRECTINPUTDEVICE8  g_lpDIDevice; // the direct input device

#define KEYDOWN(name, key) (name[key] & 0x80)
char buffer[256];

vector<string> DeviceList;

//float originX = 0.0f, originY = -1.41f, originZ = 0.0f;

bool moving = false;

float gravity = -0.00490;

float time_unit = 1;

float forceXinc = 0.00294;
float forceYinc = 0.00392;

float vm_Y = 0.24;
float vm_X = 0.05;

float forceY = 0.0;
float forceX = 0.0;

float vi_Y = 0.0;
float vi_X = 0.0;

float transY = 0.0;
float transX = 0.0;


BOOL CALLBACK EnumDevicesCallback( const DIDEVICEINSTANCE* pdidInstance,
                                     VOID* pContext )
{
    HRESULT hr;

    hr = g_lpDI->CreateDevice( pdidInstance->guidInstance, &g_lpDIDevice, NULL );

    if( FAILED(hr) ) 
        return DIENUM_STOP;
	else
	{
		// add the current device to the vector
		DeviceList.push_back(pdidInstance->tszInstanceName);
	}
    return DIENUM_CONTINUE;
}

void Name_Devices()
{
		// create a temporary string
	string tempString;

	// Loop through the vector of device names and put them in tempstring
	tempString = "List of Installed Devices\n";
	for (unsigned int i=0; i < DeviceList.size(); i++)
	{
		tempString += DeviceList[i];
		tempString += "\n";
	}

	// throw up a message box just to display the names of the devices
	MessageBox(NULL, tempString.c_str(), "Devices", MB_OK);
}

BOOL CALLBACK Create_DI(HINSTANCE &hInstance, HWND &wndHandle)
{
	HRESULT hr;

	// Create the DirectInput object. 
    hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, 
                            IID_IDirectInput8, (void**)&g_lpDI, NULL); 

	if FAILED(hr) return FALSE; 

	hr = g_lpDI->EnumDevices( DI8DEVCLASS_ALL, EnumDevicesCallback,
                              NULL, DIEDFL_ATTACHEDONLY );
	if FAILED (hr) return FALSE;

	hr = g_lpDI->CreateDevice(GUID_SysKeyboard, &g_lpDIDevice, NULL);
	if FAILED(hr) return FALSE;

	hr = g_lpDIDevice->SetDataFormat(&c_dfDIKeyboard);
	if FAILED(hr) return FALSE;

	hr = g_lpDIDevice->SetCooperativeLevel(wndHandle, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
	if FAILED(hr) return FALSE;

	hr = g_lpDIDevice->Acquire();
	if FAILED(hr) return FALSE;

	return TRUE;
}

BOOL CALLBACK Delete_DI(HINSTANCE &hInstance)
{
	if (g_lpDI) 
    { 
        if (g_lpDIDevice) 
        { 
        // Always unacquire device before calling Release(). 
            g_lpDIDevice->Unacquire(); 
            g_lpDIDevice->Release();
            g_lpDIDevice = NULL; 
        } 
        g_lpDI->Release();
        g_lpDI = NULL; 
    } 

	return TRUE;
}

XandY Get_Input(HINSTANCE &hInstance, float &forceY, float &forceX, float &vi_Y, float &vi_X, float &transY, float &transX)
{
	HRESULT hr;
	XandY temp;


	hr = g_lpDIDevice->GetDeviceState(sizeof(buffer), (LPVOID)&buffer);

		if (KEYDOWN(buffer, DIK_UP))
			{
				//transY += 0.1;
				//moving = true;
				
				if(forceY < forceYinc * 10)
				{
					forceY += (forceYinc * 2);
				}	
			}
			else
			{
				forceY = 0;

				// went to bounce code
			}

			if (KEYDOWN(buffer, DIK_DOWN))
			{
				/*
				if(transY > 0)
				{
					transY -= 0.1;
				}
				if(transY < 0)
				{
					transY = 0;
				}
				*/

				forceY = 0;
				vi_Y *= 0.98;



				//moving = true;
				// need to figure slowdown code
			}

//////////////////////////////

//			BOUNCE CODE

			if(moving == false)
			{
				if(transY > -1)
				{
					//transY -= 0.1;
					/*if(vi_Y > vm_Y)
					{
						vi_Y = vm_Y;
					}
					transY += vi_Y + 0.5 * (forceY + gravity) * time_unit;
					vi_Y = vi_Y + gravity * time_unit;*/
				}
				else
				{
					//if(transY <= -1)
					//{
					//	vi_Y *= -1;
					//	transY += vi_Y + 0.5 * (forceY + gravity) * time_unit;
					//	vi_Y = vi_Y + gravity * time_unit;

					//	/*if(transY < 0)
					//	{
					//		transY = 0;
					//	}*/
					//}
				}
			}
			else
			{
				moving = false;
			}
			

//////////////////////////////

			if (KEYDOWN(buffer, DIK_RIGHT))
			{
				//transX += 0.1;

				if(vi_X > vm_X)
				{
					vi_X = vm_X;
				}
				if (forceX >= -gravity * 0.5)
				{
					forceX = -gravity * 0.5;
				}
				else
				{
					forceX += forceXinc;
				}
				transX += vi_X + 0.5 * forceX * time_unit;
				vi_X = vi_X + forceX * time_unit;
			}
			else if (KEYDOWN(buffer, DIK_LEFT))
			{
				//transX -= 0.1;

				if(vi_X < -vm_X)
				{
					vi_X = -vm_X;
				}
				if (forceX <= gravity * 0.25)
				{
					forceX = gravity * 0.25;
				}
				else
				{
					forceX -= forceXinc;
				}
				transX += vi_X + 0.5 * forceX * time_unit;
				vi_X = vi_X + forceX * time_unit;
			}
			else
			{
				forceX = 0;
				vi_X *= 0.98;

				//if(vi_X < 0.0000001)
				//{
				//	vi_X = 0;
				//}

				transX += vi_X + 0.5 * forceX * time_unit;
			}

			

			if (KEYDOWN(buffer, DIK_SPACE))
			{
				// this code dampens the bounce, but I need a code that heightens the bounce
				/*if(transY <= 0.2)
				{
					vi_Y += 0.01;
				}*/
				// this code increases the bounce but it doesn't really act realistically
				// maybe it should modify the force of the rebound instead of the pure v?
				if(transY <= 0.2)
				{
					vi_Y *= 1.01;
				}
			}

			if(KEYDOWN(buffer, DIK_ESCAPE))
				PostQuitMessage(0);

			temp.transX = transX;
			temp.transY = transY;

			return temp;
}